#include "PadListModel.h"

#include "StringFormatter.h"

#include "LeIpc2581/enumtranslator.h"
#include "LeIpc2581/Pad.h"

#include <QDebug>
#include <QHash>
#include <QSet>

struct SetItem
{
    SetItem() {}
    explicit SetItem(const Ipc2581b::Pad *pad, Ipc2581b::PadUsage usage = Ipc2581b::PadUsage::None):
        pad(pad), usage(usage)
    {}

    const Ipc2581b::Pad *pad = nullptr;
    Ipc2581b::PadUsage usage = Ipc2581b::PadUsage::None;
};

class PadListModelPrivate
{
    Q_DISABLE_COPY(PadListModelPrivate)
    Q_DECLARE_PUBLIC(PadListModel)
    PadListModel * const q_ptr;

    explicit PadListModelPrivate(PadListModel *model):
        q_ptr(model)
    {}

    QList<SetItem> m_data;

    inline void clear()
    {
        m_data.clear();
    }
};

PadListModel::PadListModel(QObject *parent):
    QAbstractTableModel(parent),
    d_ptr(new PadListModelPrivate(this))
{
}

PadListModel::~PadListModel()
{

}

void PadListModel::addPad(const Ipc2581b::Pad *pad)
{
    Q_D(PadListModel);
    d->m_data.append(SetItem(pad));
}

void PadListModel::clear()
{
    Q_D(PadListModel);

    beginResetModel();
    d->clear();
    endResetModel();
}

QVariant PadListModel::headerData(int section, Qt::Orientation orientation, int role) const
{
    if (orientation != Qt::Horizontal)
        return QVariant();

    if (role != Qt::DisplayRole)
        return QVariant();

    switch (section)
    {
        case PadstackColumn:
            return "Padstack";
        case UsageColumn:
            return "Usage";
        case TransformColumn:
            return "Transform";
        case LocationColumn:
            return "Location";
        case ComponentColumn:
            return "Component";
        case PinColumn:
            return "Pin";
        default:
            return QVariant();
    }
}

int PadListModel::rowCount(const QModelIndex &parent) const
{
    Q_D(const PadListModel);

    if (parent.isValid())
        return 0;

    return d->m_data.count();
}

int PadListModel::columnCount(const QModelIndex &parent) const
{
    if (parent.isValid())
        return 0;

    return ColumnCount;
}

QVariant PadListModel::data(const QModelIndex &index, int role) const
{
    if (!index.isValid())
        return QVariant();

    if (index.row() < 0 || index.row() >= rowCount())
        return QVariant();

    Q_D(const PadListModel);
    const SetItem item = d->m_data.value(index.row());
    const Ipc2581b::Pad *pad = item.pad;

    switch (role)
    {
        case Qt::DisplayRole:
            switch (index.column())
            {
                case PadstackColumn:
                    return pad->padstackDefRef; // optional?
                case UsageColumn:
                    return Ipc2581b::EnumTranslator::padUsageText(item.usage);
                case TransformColumn:
                    if (pad->xformOptional.hasValue)
                        return createTransform(pad->xformOptional.value);
                    return QVariant();
                case LocationColumn:
                    return StringFormatter::pointF(pad->location);
                case ComponentColumn:
                    if (!pad->pinRefOptional.hasValue)
                        return QVariant();
                    if (!pad->pinRefOptional.value->componentRefOptional.hasValue)
                        return QVariant();
                    return pad->pinRefOptional.value->componentRefOptional.value;
                case PinColumn:
                    if (!pad->pinRefOptional.hasValue)
                        return QVariant();
                    return pad->pinRefOptional.value->pin;
                default:
                    return QVariant();
            }
        case Qt::EditRole:
            switch (index.column())
            {
                case PadstackColumn:
                    return pad->padstackDefRef;
                case UsageColumn:
                    return QVariant::fromValue<Ipc2581b::PadUsage>(item.usage);
                case TransformColumn:
                    if (pad->xformOptional.hasValue)
                        return createTransform(pad->xformOptional.value);
                    return QVariant();
                case LocationColumn:
                    return QPointF(pad->location->x, pad->location->y);
                case ComponentColumn:
                    if (!pad->pinRefOptional.hasValue)
                        return QVariant();
                    if (!pad->pinRefOptional.value->componentRefOptional.hasValue)
                        return QVariant();
                    return pad->pinRefOptional.value->componentRefOptional.value;
                case PinColumn:
                    if (!pad->pinRefOptional.hasValue)
                        return QVariant();
                    return pad->pinRefOptional.value->pin;
                default:
                    return QVariant();
            }
        default:
            return QVariant();
    }
}
